package cn.qingyun.gis.modules.scenes.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.qingyun.gis.exception.CommonException;
import cn.qingyun.gis.modules.scenes.contant.UniAddrRegionLevel;
import cn.qingyun.gis.modules.scenes.entity.PoiScenario;
import cn.qingyun.gis.modules.scenes.entity.PoiScenarioProofread;
import cn.qingyun.gis.modules.scenes.entity.PoiUpdateLog;
import cn.qingyun.gis.modules.scenes.entity.UniAddrRegion;
import cn.qingyun.gis.modules.scenes.mapper.PoiUpdateLogMapper;
import cn.qingyun.gis.modules.scenes.service.IPoiScenarioProofreadService;
import cn.qingyun.gis.modules.scenes.service.IPoiScenarioService;
import cn.qingyun.gis.modules.scenes.service.IPoiUpdateLogService;
import cn.qingyun.gis.modules.scenes.service.IUniAddrRegionService;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.locationtech.jts.geom.Geometry;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
@DS("scenes_offensive")
public class PoiUpdateLogServiceImpl extends ServiceImpl<PoiUpdateLogMapper, PoiUpdateLog> implements IPoiUpdateLogService {

    @Resource
    private IUniAddrRegionService iUniAddrRegionService;
    @Resource
    private IPoiScenarioService iPoiScenarioService;
    @Resource
    private IPoiScenarioProofreadService iPoiScenarioProofreadService;

    @Override
    public void doUpdateGrid() {
        try {
            // 微网格更新
            List<UniAddrRegion> microGridRegions = iUniAddrRegionService.selectCodeChanged(UniAddrRegionLevel.MICRO_GRID);
            if (CollUtil.isNotEmpty(microGridRegions)) {
                for (UniAddrRegion region : microGridRegions) {
                    Geometry regionWkt = region.getWkt();
                    String microGridCode = region.getCode();
                    String gridCode = region.getParentCode();
                    String districtCode = iUniAddrRegionService.getParentCode(gridCode);
                    String cityCode = iUniAddrRegionService.getParentCode(districtCode);

                    if (CharSequenceUtil.isBlank(microGridCode)
                            || CharSequenceUtil.isBlank(gridCode)
                            || CharSequenceUtil.isBlank(districtCode)
                            || CharSequenceUtil.isBlank(cityCode)
                            || ObjectUtil.isNull(regionWkt)) {
                        continue;
                    }

                    // 查询出变更的数据
                    QueryWrapper<PoiScenario> queryWrapper = new QueryWrapper<>();
                    queryWrapper.lambda()
                            .apply("st_within(points, st_geometryfromtext({0}, 4326))", regionWkt.toText())
                            .ne(PoiScenario::getMicroGridCode, microGridCode);

                    List<PoiScenario> scenarios = iPoiScenarioService.list(queryWrapper);
                    if (CollUtil.isNotEmpty(scenarios)) {
                        List<UniAddrRegion> uniAddrRegions = iUniAddrRegionService.listByCodes(gridCode, districtCode, cityCode);
                        Map<String, String> regionMap = uniAddrRegions.stream().collect(Collectors.toMap(UniAddrRegion::getCode, UniAddrRegion::getName, (a, b) -> a));
                        for (PoiScenario scenario : scenarios) {
                            scenario.setMicroGridCode(microGridCode);
                            scenario.setMicroGridName(region.getName());
                            scenario.setGridCode(gridCode);
                            scenario.setGridName(regionMap.get(gridCode));
                            scenario.setRegionDisCode(districtCode);
                            scenario.setRegionDis(regionMap.get(districtCode));
                            scenario.setRegionCityCode(cityCode);
                            scenario.setRegionCity(regionMap.get(cityCode));
                            scenario.setUpdateTime(DateUtil.date());
                        }

                        iPoiScenarioService.updateBatchById(scenarios);

                        QueryWrapper<PoiScenarioProofread> proofreadQueryWrapper = new QueryWrapper<>();
                        proofreadQueryWrapper.lambda()
                                .ne(PoiScenarioProofread::getRegionCityCode, cityCode)
                                .in(PoiScenarioProofread::getPoiScenarioId, scenarios.stream().map(PoiScenario::getId).collect(Collectors.toSet()));
                        List<PoiScenarioProofread> proofreads = iPoiScenarioProofreadService.list(proofreadQueryWrapper);
                        if (CollUtil.isNotEmpty(proofreads)) {
                            for (PoiScenarioProofread proofread : proofreads) {
                                proofread.setRegionCityCode(cityCode);
                            }
                            iPoiScenarioProofreadService.updateBatchById(proofreads);
                        }
                        this.saveLog("数据更新成功", true, region.getCode(), scenarios.size());
                    }
                }
            }

            // 网格更新
            List<UniAddrRegion> gridRegions = iUniAddrRegionService.selectCodeChanged(UniAddrRegionLevel.GRID);
            if (CollUtil.isNotEmpty(gridRegions)) {
                for (UniAddrRegion region : gridRegions) {
                    Geometry regionWkt = region.getWkt();
                    String gridCode = region.getCode();
                    String districtCode = iUniAddrRegionService.getParentCode(gridCode);
                    String cityCode = iUniAddrRegionService.getParentCode(districtCode);

                    if (CharSequenceUtil.isBlank(gridCode)
                            || CharSequenceUtil.isBlank(districtCode)
                            || CharSequenceUtil.isBlank(cityCode)
                            || ObjectUtil.isNull(regionWkt)) {
                        continue;
                    }

                    // 查询出变更的数据
                    QueryWrapper<PoiScenario> queryWrapper = new QueryWrapper<>();
                    queryWrapper.lambda()
                            .apply("st_within(points, st_geometryfromtext({0}, 4326))", regionWkt.toText())
                            .ne(PoiScenario::getGridCode, gridCode);

                    List<PoiScenario> scenarios = iPoiScenarioService.list(queryWrapper);
                    if (CollUtil.isNotEmpty(scenarios)) {
                        List<UniAddrRegion> uniAddrRegions = iUniAddrRegionService.listByCodes(gridCode, districtCode, cityCode);
                        Map<String, String> regionMap = uniAddrRegions.stream().collect(Collectors.toMap(UniAddrRegion::getCode, UniAddrRegion::getName, (a, b) -> a));
                        for (PoiScenario scenario : scenarios) {
                            scenario.setGridCode(gridCode);
                            scenario.setGridName(regionMap.get(gridCode));
                            scenario.setRegionDisCode(districtCode);
                            scenario.setRegionDis(regionMap.get(districtCode));
                            scenario.setRegionCityCode(cityCode);
                            scenario.setRegionCity(regionMap.get(cityCode));
                        }

                        iPoiScenarioService.updateBatchById(scenarios);

                        QueryWrapper<PoiScenarioProofread> proofreadQueryWrapper = new QueryWrapper<>();
                        proofreadQueryWrapper.lambda()
                                .ne(PoiScenarioProofread::getRegionCityCode, cityCode)
                                .in(PoiScenarioProofread::getPoiScenarioId, scenarios.stream().map(PoiScenario::getId).collect(Collectors.toSet()));
                        List<PoiScenarioProofread> proofreads = iPoiScenarioProofreadService.list(proofreadQueryWrapper);
                        if (CollUtil.isNotEmpty(proofreads)) {
                            for (PoiScenarioProofread proofread : proofreads) {
                                proofread.setRegionCityCode(cityCode);
                            }
                            iPoiScenarioProofreadService.updateBatchById(proofreads);
                        }
                        this.saveLog("数据更新成功", true, region.getCode(), scenarios.size());
                    }
                }
            }
        } catch (Exception e) {
            this.saveLog("数据更新失败," + e.getMessage(), false, null, 0);
            throw new CommonException("数据更新失败！" + e.getMessage());
        }
    }

    /**
     * 保存操作日志
     *
     * @param message 信息
     * @param success 是否成功标识
     * @param code    操作区划码
     * @param count   操作的个数
     */
    private void saveLog(String message, Boolean success, String code, Integer count) {
        PoiUpdateLog poiUpdateLog = new PoiUpdateLog();
        poiUpdateLog.setCreatTime(new Date());
        poiUpdateLog.setSuccess(success);
        poiUpdateLog.setSuccessCount(count);
        poiUpdateLog.setCode(code);
        poiUpdateLog.setType(2);
        poiUpdateLog.setMessage(message);

        this.save(poiUpdateLog);
    }
}
